﻿// <copyright file="Equality.cs" company="Community Combat Simulator">
//    Community Combat Simulator: a free combat flight simulator.
//    Copyright (C) 2008 Aaron Schinkowitch
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see http://www.gnu.org/licenses/.
// </copyright>
namespace CCSim.Util
{
    using System;

    /// <summary>
    /// Performs equality checks.
    /// </summary>
    public class Equality
    {
        /// <summary>
        /// The standard equality factor.
        /// </summary>
        public const double EqualityFactor = 1E-10;
        
        /// <summary>
        /// Point at which the equality factor begins to be scaled.
        /// </summary>
        private const double ScaleCutoff = 1;
        
        /// <summary>
        /// Checks if two doubles are approximately equal within an error margin. An equality factor
        /// is defined for deterimining if the numbers are equal. For numbers whose magnitude is 
        /// less than or equal to 1, the numbers are equal if there difference is less than the equality 
        /// factor. For numbers larger than 1, the numbers are equal if their difference is less the
        /// the magnitude of the largest number times the equality factor.
        /// </summary>
        /// <param name="value1">The first number.</param>
        /// <param name="value2">The second number.</param>
        /// <param name="equalityFactor">Factor for determining equality.</param>
        /// <returns>true if the numbers are approximately equal.</returns>
        public bool RoughlyEqual(double value1, double value2, double equalityFactor)
        {
            if (value1 == value2) 
            {
                return true;
            }
            
            double acceptableDifference = equalityFactor;

            double maxMagnitude = Math.Max(Math.Abs(value1), Math.Abs(value2));
            
            if (maxMagnitude > ScaleCutoff) 
            {
                acceptableDifference *= maxMagnitude;
            }
            
            return Math.Abs(value1 - value2) < acceptableDifference;
        }
        
        /// <summary>
        /// Checks if two numbers are roughly equal using the standard equality factor.
        /// </summary>
        /// <param name="value1">The first number.</param>
        /// <param name="value2">The second number.</param>
        /// <returns>true if the numbers are approximately equal.</returns>
        /// <seealso cref="EqualityFactor">The standard equality factor.</seealso>
        public bool RoughlyEqual(double value1, double value2)
        {
            return this.RoughlyEqual(value1, value2, EqualityFactor);
        }
    }
}
